import type { RouteRecordRaw } from "vue-router";

/**
 * @description: 树结构扁平化(vue-router默认不支持多层嵌套,该方法用于将多层嵌套的路由扁平化)
 * @param {RouteRecordRaw} routes
 * @param {RouteRecordRaw} result
 * @return {*}
 */
export const treeTransferRoutes = (routes: RouteRecordRaw[], result: RouteRecordRaw[] = []) => {
  routes.filter(Boolean).forEach((item) => {
    // 加入当前路由对象
    const newItem = { ...item };
    delete newItem.children;
    result.push(newItem);
    // 若有子路由，则递归处理
    if (item?.children && item.children?.length > 0) {
      treeTransferRoutes(item.children, result);
    }
  });
  return result;
};

/**
 * @description: 获取路由所有路径
 * @param {RouteRecordRaw} route
 * @return {*}
 */
export const getRoutePaths = (route: RouteRecordRaw) => {
  const routePaths = treeTransferRoutes([route]);

  return routePaths.map((x) => x.path);
};

/**
 * @description: 校验路由合规性
 * @param {RouteRecordRaw} route
 * @return {*}
 */
export const verifyRoutesCompliance = (route: RouteRecordRaw) => {
  const name = (route.meta?.name || route.name || route.path) as string;

  // 检验名称是否重复
  const routes = treeTransferRoutes([route]);
  if (!route.name) {
    throw new Error(`${name}端路由name字段不能为空`);
  }
  // 校验meta.name是否为空
  if (!route.meta?.name) {
    throw new Error(`${name}端路由meta.name字段不能为空`);
  }
  // 校验路径重复
  const routePaths = routes.map((x) => x.path);
  if (new Set(routePaths).size !== routePaths.length) {
    throw new Error(`${name}端路由路径[path]不能重复`);
  }
  // 校验meta.name是否重复
  const routeNames = routes.map((x) => x.name);
  if (new Set(routeNames).size !== routePaths.length) {
    throw new Error(`${name}端路由名称[meta.name]不能重复`);
  }
  // 校验未收录字段
  const routeAlias = routes.map((x) => x.alias).filter(Boolean);
  const beforeEnter = routes.map((x) => x.beforeEnter).filter(Boolean);
  const beforeProps = routes.map((x) => x.props).filter(Boolean);
  if (routeAlias.length || beforeEnter.length || beforeProps.length) {
    throw new Error(`${name}端路由不推荐使用alias、beforeEnter、props字段，动态路由未收录该字段，请使用meta字段`);
  }
  // 校验父级重定向
  const routeRedirect = routes.find((x) => !Object.keys(x).includes("component") && !x.redirect);
  if (routeRedirect) {
    throw new Error(`${name}端路由[${String(routeRedirect.meta?.name || routeRedirect.name || routeRedirect.path)}]未配置重定向路径`);
  }
  // 校验affix字段是否合规
  const routeAffix = routes.filter((x) => x.meta?.affix);
  const it = routeAffix.find((x) => x.meta?.affix && !Object.keys(x).includes("component"));
  if (it) {
    throw new Error(`${name}端路由[${String(it?.meta?.name || it.name)}]父级路由不推荐使用affix字段，affix字段应应用在页面路由上`);
  }
  if (route.meta?.affix) {
    throw new Error(`${name}端路由根路由不推荐使用affix字段，affix字段应应用在页面路由上`);
  }
};

/**
 * @description: 校验公共路由合规性
 * @param {RouteRecordRaw[]} routes
 * @return {*}
 */
export const verifyPublicRoutesCompliance = (routes: RouteRecordRaw[]) => {
  if (routes.find((x) => x.name)) {
    throw new Error(`公共路由不推荐属性name字段`);
  }
};
